package webprog;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import net.sf.json.JSONObject;

import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.WsOutbound;

import de.fhwgt.quiz.application.Player;
import de.fhwgt.quiz.application.Question;
import de.fhwgt.quiz.application.Quiz;
import de.fhwgt.quiz.error.QuizError;
import de.fhwgt.quiz.loader.FilesystemLoader;
/**
 * 
 * @author Gennadi Heimann
 * Klasse verarbeitet die empfangende Daten von Client 
 *
 */
public class DatenSendenUndEmpfangen extends MessageInbound{  

	WsOutbound socket;
	private FilesystemLoader filesystemLoader;
	private String katalogName;
	private Quiz quiz;
	private QuizError quizError;
	private Collection <Player> players;
	private Player superPlayer;
	private JSONObject typ1Json, typ3Json, typ5Json, typ6Json, typ7Json, 
						typ9Json, fehlerJson;
	private Question nachsteFrage;
	private long ausgewahlteAntwort, richtigeAntwort;
	private Verbindungsliste ver;
	private List<DatenSendenUndEmpfangen> websockets;
	private int id;
	private WebSocket websocket;
	
	public DatenSendenUndEmpfangen(int id, WebSocket websocket) {
		this.id = id;
		this.websocket = websocket;
		quiz = Quiz.getInstance();
		filesystemLoader = new FilesystemLoader("frageCatalog");
		quiz.initCatalogLoader(filesystemLoader);
		quizError = new QuizError();
		fehlerJson = new JSONObject();
		ver = Verbindungsliste.getInstance();
		players =  quiz.getPlayerList();
	}
		
	@Override
	public void onOpen(WsOutbound empfangen){
		System.out.println("#Websocket# onOpen");
	}
	@Override
	public void onClose(int status){
		System.out.println("#Websocket Nr: " + id + " # onClose");
		ByteBuffer send = null;
		//Name Taken
		if(ver.getNameTaken()){
			System.out.println("1name taken");
			ver.removeVerbinding(this);
			try {
				this.getWsOutbound().close(0, send);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			websocket.idDecrenent();
			ver.nameTakenZurucksetzen();
		}
		for(Player pl : players){
			if(pl.getId() == id){
				ver.removeVerbinding(this);
				System.out.println("Player mit id: " + pl.getId()+ " entfernen");
				quiz.removePlayer(pl, quizError);
				//prüfen ob der Superuser ausgestiegen ist
				if(pl.getId() == 0){
					fehlerJson.put("typ", "0");
					fehlerJson.put("fatal", "1");
					fehlerJson.put("fehlerNachricht", "Spielleiter hat das Spiel verlassen");
					broadcast(fehlerJson.toString());
					websocket.idZurucksetzen();
					for(DatenSendenUndEmpfangen verbindung: websockets){
						try {
							verbindung.getWsOutbound().close(0, send);
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					websockets.removeAll(websockets);
					System.out.println("websocket geschlossen " + players.size() 
							+ "  " + websockets.size());
				}
				if(quizError.isSet()){
					System.out.println("##Error## " + quizError.getDescription()
							+ ". Status: " + quizError.getStatus());
					//Alle ausgestiegen sind
					if(quizError.getStatus() == 8){
						fehlerJson.put("typ", "0");
						fehlerJson.put("fatal", "1");
						fehlerJson.put("fehlerNachricht", "Alle Spieler haben sich abgemeldet. Spielende.");
						broadcast(fehlerJson.toString());
						websocket.idZurucksetzen();
						for(DatenSendenUndEmpfangen verbindung: websockets){
							try {
								verbindung.getWsOutbound().close(0, send);
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
						websockets.removeAll(websockets);
						System.out.println("websocket geschlossen " + players.size() 
								+ "  " + websockets.size());
					}
					if(quizError.getStatus() == 4){
						websocket.idZurucksetzen();
					}
				}
				quiz.signalPlayerChange();
				try {
					this.getWsOutbound().close(0, send);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	@Override
	protected void onBinaryMessage(ByteBuffer arg0) throws IOException {
		throw new UnsupportedOperationException(
				"Websocket Unterstüzt die binäre Daten nicht.");
	}

	@SuppressWarnings("static-access")
	@Override
	protected void onTextMessage(CharBuffer message) throws IOException {
		System.out.println("Websocket hat empfangen: " + message);
		char typ = message.charAt(0);
		switch (typ) {
			case '1' : {
				System.out.println("#Case 1#  #PlayerId#: " + id);
				katalogName = message.toString().substring(1, message.toString().length());
				System.out.println("Ausgewählte Katalog: " + katalogName);
				typ1Json = new JSONObject();
				for(Player pl: players){
					if(pl.isSuperuser()){
						superPlayer = pl;
						System.out.println("PlayerId: " + pl.getId() + 
								"und Player Name: " + pl.getName());
						quiz.changeCatalog(superPlayer, katalogName, quizError);
						if(quizError.isSet()){
							System.out.println("##Error## " + quizError.getDescription()
									+ ". Status: " + quizError.getStatus());
						}
						if(quiz.startGame(superPlayer, quizError)){
							System.out.println("Spiel hat gestartet");
							typ1Json.put("typ", "1");
							broadcast(typ1Json.toString());
						}else{
							System.out.println("Kein zweite Spieler");
							fehlerJson.put("typ", "0");
							fehlerJson.put("fatal", "0");
							fehlerJson.put("fehlerNachricht", "Kein zweite Spieler");
							message = message.wrap(fehlerJson.toString());
							this.getWsOutbound().writeTextMessage(message);
						}
						if(quizError.isSet()){
							System.out.println("##Error## " + quizError.getDescription()
									+ ". Status: " + quizError.getStatus());		
						}
					}
				}
				break;
			}
			case '2': {
				System.out.println("#Case 2#  #PlayerId#: " + id);
				for(Player pl : players){
					if(pl.getId() == id){
						ZeitAbgelaufen task = new ZeitAbgelaufen(this, pl);
						quizError.set(null);
						typ3Json = new JSONObject();
						nachsteFrage = quiz.requestQuestion(pl, task, quizError);
						if(quizError.isSet()){
							System.out.println("##Error## " + quizError.getDescription()
									+ ". Status: " + quizError.getStatus());
						}
						if(nachsteFrage == null){
							System.out.println("Keine Frage mehr");
							typ6Json = new JSONObject();
							typ6Json.put("typ", "6");
							typ6Json.put("punkten", pl.getScore());
							typ6Json.put("id", pl.getId());
							message = message.wrap(typ6Json.toString());
							this.getWsOutbound().writeTextMessage(message);
							boolean flag = quiz.setDone(pl);
							if(flag == true){
								typ7Json = new JSONObject();
								typ7Json.put("typ", "7");
								List< Player > list = new ArrayList< Player >( players );
								Comparator<Player> comp = new PlayerComperator();
								Collections.sort(list, comp);
								int count = 0;
								for(Player p: list){
									typ7Json.put("id" + p.getId(), count +1);
									count++;
								}
								broadcast(typ7Json.toString());
								ByteBuffer send = null;
								websocket.idZurucksetzen();
								websockets = ver.getVerbindungen();
								for(Player plr: players){
									quiz.removePlayer(plr, quizError);
								}
								for(DatenSendenUndEmpfangen verbindung: websockets){
									System.out.println("#Socket geschlossen#");
									try {
										verbindung.getWsOutbound().close(0, send);
									} catch (IOException e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
								}
								websockets.removeAll(websockets);
							}
						}else{
							System.out.println("#Nächste Frage#: " + nachsteFrage);
							typ3Json.accumulate("typ", "3");
							typ3Json.accumulate("frage", nachsteFrage.getQuestion());
							typ3Json.accumulate("antwort", nachsteFrage.getAnswerList());
							typ3Json.accumulate("timeout", nachsteFrage.getTimeout());
							message = message.wrap(typ3Json.toString());
							this.getWsOutbound().writeTextMessage(message);
						}
					}
				}
				break;
			}
			case '4' : {
				System.out.println("#case 4#  #PlayerId#: " + id);
				typ5Json = new JSONObject();
				ausgewahlteAntwort = Integer.parseInt(message.toString().substring(1, 2));
				for(Player plr : players){
					if(plr.getId() == id){
						richtigeAntwort = quiz.answerQuestion(plr, ausgewahlteAntwort, quizError);
						if(quizError.isSet()){
							System.out.println("##Error## " + quizError.getDescription()
									+ ". Status: " + quizError.getStatus());
						}
						typ5Json.put("typ", "5");
						typ5Json.put("korrekt", richtigeAntwort);
						message = message.wrap(typ5Json.toString());
						this.getWsOutbound().writeTextMessage(message);
						quiz.signalPlayerChange();
					}
				}
				break;
			}
			case '8': {
				System.out.println("#case 8#  #PlayerId#: " + id);
				char katalog = message.charAt(1);
				typ9Json = new JSONObject();
				typ9Json.put("typ", "9");
				typ9Json.put("cat", katalog);
				broadcast(typ9Json.toString());
				break;
			}
			default:{
				System.out.println("Fehler!! Unbekannte Typ" );
			}
		}
	}
	public void zeitAbgelaufen(DatenSendenUndEmpfangen data, Player player){
		typ5Json = new JSONObject();
		richtigeAntwort = quiz.answerQuestion(player, 1, quizError);
		if(quizError.isSet()){
			System.out.println("##Error## " + quizError.getDescription()
					+ ". Status: " + quizError.getStatus());
		}
		typ5Json.put("typ", "5");
		typ5Json.put("korrekt", richtigeAntwort);
		CharBuffer senden = CharBuffer.wrap(typ5Json.toString());
		try {
			data.getWsOutbound().writeTextMessage(senden);
		} catch (IOException e) {
			System.out.println("##Websocket ist geschlossen##");
		}
	}
	public void broadcast(String message){
		System.out.println("Broadcast schickt: " + message);
		websockets = ver.getVerbindungen();
		for(DatenSendenUndEmpfangen verbindung : websockets){
			CharBuffer senden = CharBuffer.wrap(message);
			try {
				verbindung.getWsOutbound().writeTextMessage(senden);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}	
}